home *** CD-ROM | disk | FTP | other *** search
/ Mac Cube 4: Multimedia Applications / MacCube Volume 4: Multimedia Applications.iso / Graphics / POV Ray / POVSOURCE / SOURCE / POVMalloc.c < prev    next >
Text File  |  1994-02-04  |  20KB  |  713 lines

  1. /*==============================================================================
  2. Project:    POV-Ray
  3.  
  4. Version:    2.2
  5.  
  6. File:        POVMalloc.c
  7.  
  8. Description:
  9. Library routines and definitions to re-route the Std C library
  10. calls to malloc/free, track them, and handle garbage-collection.
  11.  
  12. There are some compile-time flags in here of importance.  They
  13. are not defined (off), but if defined, will change the behavior
  14. of the memory allocation code:
  15.  
  16. USE_NATIVE_MALLOC - if defined, will use the Mac's NewPtr() calls
  17. instead of C's malloc().  This turns out to be a little slower,
  18. but leaves a cleaner heap.  malloc allocates chunks that are
  19. not actually discarded when free is called.
  20.  
  21. USE_MEMHANDLES - This allocates handles instead of pointers, then
  22. locks and derefs them.
  23.  
  24. USE_MEMTAGS - if defined, will add a 4 byte tag to each memory
  25. chunk allocated, and insure that the de-allocation of memory has
  26. this tag.  This will detect any free calls that are passed bad
  27. pointers.
  28.  
  29. MALLOC_TRACE - Adds info about the source file/line # of allocation
  30. in the block allocated, so it can be displayed on cleanup
  31. ------------------------------------------------------------------------------
  32. Author:
  33.     Jim Nitchals and Eduard [esp] Schwan
  34. ------------------------------------------------------------------------------
  35.     from Persistence of Vision Raytracer
  36.     Copyright 1993 Persistence of Vision Team
  37. ------------------------------------------------------------------------------
  38.     NOTICE: This source code file is provided so that users may experiment
  39.     with enhancements to POV-Ray and to port the software to platforms other 
  40.     than those supported by the POV-Ray Team.  There are strict rules under
  41.     which you are permitted to use this file.  The rules are in the file
  42.     named POVLEGAL.DOC which should be distributed with this file. If 
  43.     POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  44.     Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  45.     Forum.  The latest version of POV-Ray may be found there as well.
  46.  
  47.     This program is based on the popular DKB raytracer version 2.12.
  48.     DKBTrace was originally written by David K. Buck.
  49.     DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  50. ------------------------------------------------------------------------------
  51. More Info:
  52.     This Macintosh version of POV-Ray was created and compiled by Jim Nitchals
  53.     (Think 5.0) and Eduard Schwan (MPW 3.2), based (loosely) on the original
  54.     port by Thomas Okken and David Lichtman, with some help from Glenn Sugden.
  55.  
  56.     For bug reports regarding the Macintosh version, you should contact:
  57.     Eduard [esp] Schwan
  58.         CompuServe: 71513,2161
  59.         Internet: jl.tech@applelink.apple.com
  60.         AppleLink: jl.tech
  61.     Jim Nitchals
  62.         Compuserve: 73117,3020
  63.         America Online: JIMN8
  64.         Internet: jimn8@aol.com -or- jimn8@applelink.apple.com
  65.         AppleLink: JIMN8
  66. ------------------------------------------------------------------------------
  67. Change History:
  68.     921023    [esp]    Created.
  69.     921202    [esp]    Added POV_need_to_reclaim() routine
  70.     921221    [esp]    Added BeVerbose parm to POV_Reclaim routine
  71.     930423    [esp]    Added low-memory check in malloc/calloc (MIN_SAFE_BYTES).
  72.     930618    [esp]    Added USE_NATIVE_MALLOC code (again) and renamed USE_MEMTAGS
  73.     931001    [esp]    version 2.0 finished (Released on 10/4/93)
  74.     931020    [esp]    Added realloc function
  75.     931020    [esp]    Began adding experimental NewHandle/MoveHHi (USE_MEMHANDLES) code
  76.     931116    [esp]    Added out-of-mem handling code (gReserveBuffer, HandleOutOfMem)
  77.     931119    [djh]    Added <ToolUtils.h> for PPC compatibility
  78. ==============================================================================*/
  79.  
  80. #define POVMALLOC_C
  81.  
  82. #include <types.h>
  83. #include <stdlib.h>    // malloc
  84. #include <memory.h>    // NewPtr
  85. #include <errors.h>    // memFullErr
  86. #include <ToolUtils.h> // watchCursor
  87.  
  88. #include "POVMalloc.h"
  89. #include "POVLib.h"
  90.  
  91.  
  92. // out-of-mem reserve space
  93. #define RESERVE_MEM_SIZE    60000L
  94.  
  95. // This defines the lowest free memory is allowed to get before
  96. // malloc & calloc fail.  This guarantees some free heap space for
  97. // error recovery.
  98. #define    MIN_SAFE_BYTES        60000L
  99.  
  100. #if USE_MEMTAGS
  101. // long int tag used to detect bad ptrs passed to free()
  102. #define MALLOC_TAG        'MTAG'
  103. #endif // USE_MEMTAGS
  104.  
  105.  
  106. // Memory allocation tracking (Garbage Collection)
  107. static Handle        gReserveBuffer = NULL;
  108. static Boolean        gDoMemTracking;
  109. static Boolean        gReclaiming;
  110. static long            gMallocListCount,
  111.                     gFreeListCount,
  112.                     gMallocListSize;
  113. static Ptr            *gMallocList;        // array of pointers
  114. static Ptr            *gFreeList;            // array of pointers
  115. static long            gEscapedMallocsCount = 0L;    // track # of untracked mallocs (can't garbage collect)
  116.  
  117.  
  118. void    catch_exit(int n);
  119.  
  120.  
  121. // =====================================================================
  122. void AllocateSafetyBuffer(void)
  123. {
  124.     if (gReserveBuffer == NULL)
  125.     {
  126.         gReserveBuffer = NewHandle(RESERVE_MEM_SIZE);
  127.         if (gReserveBuffer)
  128.             MoveHHi(gReserveBuffer);
  129.     }
  130. } // AllocateSafetyBuffer
  131.  
  132.  
  133. // =====================================================================
  134. void PurgeSafetyBuffer(void)
  135. {
  136.     if (gReserveBuffer)
  137.     {
  138.         DisposeHandle(gReserveBuffer);
  139.         gReserveBuffer = NULL;
  140.     }
  141. } // PurgeSafetyBuffer
  142.  
  143.  
  144. // =====================================================================
  145. OSErr POV_init_memtracking(size_t max_trackable)
  146. {
  147.     gReclaiming = false; // not reclaiming just now
  148.  
  149.     // allocate malloc() garbage collection buffers
  150.     gMallocListSize = max_trackable;
  151.     if (gMallocListSize < 500)
  152.         gMallocListSize = 500;
  153.     gMallocList  = (Ptr*) NewPtr((gMallocListSize+2L)*sizeof(Ptr));
  154.     gFreeList = (Ptr*) NewPtr((gMallocListSize+2L)*sizeof(Ptr));
  155.  
  156.     if ((gMallocList == NULL) || (gFreeList == NULL))
  157.     {
  158.         // fatal error
  159. //        displayDialog(kdlog_GenericFatalErr, "Cannot allocate memory for garbage collection",
  160. //                    gMallocListSize, ewcDoCentering, eMainDevice);
  161. //        exit_handler();
  162.         return memFullErr;
  163.     }
  164.     else
  165.     {
  166.         // unmark first item on list
  167.         *gMallocList = NULL;
  168.         gMallocListCount = 0;
  169.         *gFreeList = NULL;
  170.         gFreeListCount = 0;
  171.     }
  172.  
  173.     // allocate our safety buffer
  174.     AllocateSafetyBuffer();
  175.  
  176.     return noErr;
  177.  
  178. } // POV_init_memtracking
  179.  
  180.  
  181. // =====================================================================
  182. void POV_enable_memtracking(Boolean dotracking)
  183. {
  184.     gDoMemTracking = dotracking;
  185. } // POV_enable_memtracking
  186.  
  187.  
  188. // =====================================================================
  189. void HandleOutOfMem(void)
  190. {
  191.     // We are most likely out of memory.  For now, we will free all the
  192.     // allocated memory, and exit back to the main loop with an error.
  193.     // We could be down to 5 or 10 bytes of available memory, and to do
  194.     // anything else (like return from malloc and let the caller handle it)
  195.     // risks a hard lockup or crash!  So, first, make sure there's room
  196.     // for loading dialogs & stuff in POV_reclaim(), by dumping the buffer memory.
  197.     PurgeSafetyBuffer();
  198.  
  199.     // open some more heap space
  200.     (void)CompactMem(FreeMem());
  201.  
  202.     // beep!
  203.     SysBeep(2);
  204.  
  205.     // Now free all memory
  206.     POV_reclaim(false, NULL);
  207.  
  208.     // tell user we failed from here
  209.     puts("\n## Error! Ran out of memory.  Action aborted.");
  210.  
  211.     // reallocate our safety net for next time
  212.     AllocateSafetyBuffer();
  213.  
  214.     // now exit out of all fn calls
  215.     catch_exit(1);
  216.  
  217. } // HandleOutOfMem
  218.  
  219.  
  220. // =====================================================================
  221. #if MALLOC_TRACE
  222. void *POV_malloc(size_t size, char * src_file, short src_line_num)
  223. #else
  224. void *POV_malloc(size_t size)
  225. #endif // MALLOC_TRACE
  226. {
  227.     void    *myptr = NULL;
  228. #if USE_MEMHANDLES
  229.     Handle    myhdl = NULL;
  230. #endif
  231.  
  232.     if (MaxBlock() > MIN_SAFE_BYTES)
  233.     {
  234. #if MALLOC_TRACE
  235.         size += 32; // add room for tag file name/line #
  236. #endif // MALLOC_TRACE
  237.  
  238. #if USE_MEMTAGS
  239.         size += 4; // add room for tag MALLOC_TAG
  240. #endif // USE_MEMTAGS
  241.  
  242. #if USE_NATIVE_MALLOC
  243.  #if USE_MEMHANDLES
  244.         // use locked handles
  245.         myhdl = NewHandle(size);
  246.         if (myhdl)
  247.         {
  248.             MoveHHi(myhdl); // move it up
  249.             HLock(myhdl); // and lock it down
  250.             // it's really a handle, turn it into a pointer
  251.             myptr = *myhdl;
  252.         }
  253.  #else
  254.         // use regular pointers
  255.         myptr = NewPtr(size);
  256.  #endif // USE_MEMHANDLES
  257. #else
  258.         // use Std C Lib allocator
  259.         myptr = malloc(size);
  260. #endif // USE_NATIVE_MALLOC
  261.  
  262.         if (myptr)
  263.         { // successfully allocated it
  264.  
  265. #if MALLOC_TRACE
  266.             *(short*)myptr = src_line_num;
  267.             myptr = (void*)(((long)myptr)+2L); // point beyond line #
  268.             strcpy(myptr, src_file);
  269.             myptr = (void*)(((long)myptr)+30L); // point beyond file name
  270. #endif // MALLOC_TRACE
  271.  
  272. #if USE_MEMTAGS
  273.             *(long*)myptr = MALLOC_TAG;
  274.             myptr = (void*)(((long)myptr)+4L); // point beyond tag
  275. #endif // USE_MEMTAGS
  276.  
  277.             if (gDoMemTracking)
  278.             {  // remember this pointer for auto-disposing later
  279. #if USE_MEMHANDLES
  280.                 // remember the handle
  281.                 gMallocList[gMallocListCount] = (Ptr)myhdl;
  282. #else
  283.                 gMallocList[gMallocListCount] = myptr;
  284. #endif
  285.                 if (gMallocListCount < gMallocListSize)
  286.                     gMallocListCount++;
  287.                 else
  288.                     gEscapedMallocsCount++; // oops, overflow, one got away!
  289.             }
  290.         }
  291.     }
  292.  
  293.     // allocation was unsuccessful
  294.     if (myptr == NULL)
  295.         HandleOutOfMem();
  296.  
  297.     return myptr;
  298.  
  299. } // POV_malloc
  300.  
  301.  
  302. // =====================================================================
  303. #if MALLOC_TRACE
  304. void *POV_calloc(size_t nmemb, size_t size, char * src_file, short src_line_num)
  305. #else
  306. void *POV_calloc(size_t nmemb, size_t size)
  307. #endif // MALLOC_TRACE
  308. {
  309.     void *myptr = NULL;
  310. #if USE_MEMHANDLES
  311.     Handle    myhdl = NULL;
  312. #endif
  313.  
  314.     if (MaxBlock() > MIN_SAFE_BYTES)
  315.     {
  316. #if MALLOC_TRACE
  317.         size += 32; // add room for tag file name/line #
  318. #endif // MALLOC_TRACE
  319.  
  320. #if USE_MEMTAGS
  321.         size += 4; // add room for tag MALLOC_TAG
  322. #endif // USE_MEMTAGS
  323.  
  324. #if USE_NATIVE_MALLOC
  325.  #if USE_MEMHANDLES
  326.         // use locked handles
  327.         myptr = NewHandleClear(nmemb*size);
  328.         if (myhdl)
  329.         {
  330.             MoveHHi(myhdl); // move it up
  331.             HLock(myhdl); // and lock it down
  332.             // it's really a handle, turn it into a pointer
  333.             myptr = *myhdl;
  334.         }
  335.  #else
  336.         // use regular pointers
  337.         myptr = NewPtrClear(nmemb*size);
  338.  #endif // USE_MEMHANDLES
  339. #else
  340.         myptr = calloc(nmemb,size);
  341. #endif // USE_NATIVE_MALLOC
  342.  
  343.         if (myptr)
  344.         { // successfully allocated it 
  345. #if MALLOC_TRACE
  346.             *(short*)myptr = src_line_num;
  347.             myptr = (void*)(((long)myptr)+2L); // point beyond line #
  348.             strcpy(myptr, src_file);
  349.             myptr = (void*)(((long)myptr)+30L); // point beyond file name
  350. #endif // MALLOC_TRACE
  351.  
  352. #if USE_MEMTAGS
  353.             *(long*)myptr = MALLOC_TAG;
  354.             myptr = (void*)(((long)myptr)+4L); // point beyond tag
  355. #endif // USE_MEMTAGS
  356.  
  357.             if (gDoMemTracking)
  358.             {  // remember this pointer for auto-disposing later
  359. #if USE_MEMHANDLES
  360.                 // remember the handle
  361.                 gMallocList[gMallocListCount] = (Ptr)myhdl;
  362. #else
  363.                 gMallocList[gMallocListCount] = myptr;
  364. #endif
  365.                 if (gMallocListCount < gMallocListSize)
  366.                     gMallocListCount++;
  367.                 else
  368.                     gEscapedMallocsCount++; // oops, overflow, one got away!
  369.             }
  370.         }
  371.     }
  372.  
  373.     // allocation was unsuccessful
  374.     if (myptr == NULL)
  375.         HandleOutOfMem();
  376.  
  377.     return myptr;
  378.  
  379. } // POV_calloc
  380.  
  381.  
  382.  
  383. // =====================================================================
  384. void *POV_realloc(void * p, size_t newsize)
  385. {
  386. printf("ERROR! realloc not ready!\n");
  387. /*
  388. ---------------------------------------- not ready yet!
  389. #if USE_NATIVE_MALLOC
  390.     size_t    oldsize;
  391. #endif
  392. #if USE_MEMHANDLES
  393.     Handle    myhdl = NULL;
  394. #endif
  395.  
  396.     short    k;
  397.     void    *myptr = NULL;
  398.  
  399.     // Warn user if nil pointer passed in!
  400.     if (p == NULL)
  401.     {
  402.         printf("## Warning! Ignoring an attempt to realloc a nil pointer!\n");
  403. #if USE_MEMTAGS
  404.         DebugStr("\pTried to free a nil pointer");
  405. #endif // USE_MEMTAGS
  406.         return NULL;
  407.     }
  408.  
  409.     if (MaxBlock() > MIN_SAFE_BYTES)
  410.     {
  411. #if USE_MEMTAGS
  412.         newsize += 4; // add room for tag MALLOC_TAG
  413.         pOrig = (void*)(((long)p)-4L); // back up to tag/original position
  414.         if (*(long*)pOrig != MALLOC_TAG)
  415.         {
  416.             printf("## Error!  Tried to realloc a bad/stomped block! ($%lx)\n",pOrig);
  417.             DebugStr("\pTried to realloc a bad/stomped block 1");
  418.         }
  419. #endif // USE_MEMTAGS
  420.  
  421. #if USE_NATIVE_MALLOC
  422.  
  423.  #if USE_MEMHANDLES
  424.         // get previous size for shrink/grow check
  425.         oldsize = GetHandleSize(RecoverHandle(p));
  426.         // allocate new space... use locked handles
  427.         myhdl = (Ptr)NewHandle(newsize);
  428.  #else
  429.         // get previous size for shrink/grow check
  430.         oldsize = GetPtrSize(p);
  431.         // allocate new space... use regular pointers
  432.         myptr = NewPtr(newsize);
  433.  #endif // USE_MEMHANDLES
  434.  
  435.         if (myptr)
  436.         {
  437.  #if USE_MEMHANDLES
  438.             MoveHHi(myptr); // move it up
  439.             HLock(myptr); // and lock it down
  440.             // it's really a handle, turn it into a pointer
  441.             myptr = *(Handle)myptr;
  442.  #endif // USE_MEMHANDLES
  443.  
  444. #if USE_MEMTAGS
  445.             oldsize -= 4; // remove size of tag MALLOC_TAG, just copy data
  446.             newsize -= 4; // remove size of tag MALLOC_TAG, just copy data
  447. #endif
  448.             // copy old contents into new space (trim if less space)
  449.             BlockMove(p, myptr, (oldsize<newsize)?oldsize:newsize);
  450.  
  451.             // now release old memory...
  452.             POV_free(p);
  453.         }
  454. #else
  455.         // do the ANSI thing
  456.         myptr = realloc(p, newsize);
  457. #endif // USE_NATIVE_MALLOC
  458.  
  459.         if (myptr)
  460.         { // successfully re-allocated it
  461. #if USE_MEMTAGS
  462.             *(long*)myptr = MALLOC_TAG;
  463.             myptr = (void*)(((long)myptr)+4L); // point beyond tag
  464. #endif // USE_MEMTAGS
  465.  
  466.             if (gDoMemTracking)
  467.             {  // remember this new pointer for auto-disposing later
  468.                 gMallocList[gMallocListCount] = myptr;
  469.                 if (gMallocListCount < gMallocListSize)
  470.                     gMallocListCount++;
  471.                 else
  472.                     gEscapedMallocsCount++; // oops, overflow, one got away!
  473.             }
  474.         }
  475.     }
  476.  
  477.     // allocation was unsuccessful
  478.     if (myptr == NULL)
  479.         HandleOutOfMem();
  480.  
  481.     return myptr;
  482. ------------------------------------
  483. */
  484. } // POV_realloc
  485.  
  486.  
  487. // =====================================================================
  488. void POV_free(void *myptr)
  489. {
  490. #if USE_MEMHANDLES
  491.      Handle        myhdl = NULL;
  492. #endif // USE_MEMHANDLES
  493.  
  494.     if (myptr == NULL)
  495.     {
  496.         printf("## Warning! Ignoring an attempt to free a nil pointer!\n");
  497. #if USE_MEMTAGS
  498.         DebugStr("\pTried to free a nil pointer");
  499. #endif // USE_MEMTAGS
  500.     }
  501.     else
  502.     {
  503.  
  504. #if USE_MEMTAGS
  505.         myptr = (void*)(((long)myptr)-4L); // back up to tag
  506.         if (*(long*)myptr != MALLOC_TAG)
  507.         {
  508.             printf("## Error!  Tried to free a bad/stomped block! ($%lx)\n",myptr);
  509.             DebugStr("\pTried to free a bad/stomped block 1");
  510.         }
  511. #endif // USE_MEMTAGS
  512.  
  513. #if MALLOC_TRACE
  514.         myptr = (void*)(((long)myptr)-32L); // back up over file name/line #
  515. #endif // MALLOC_TRACE
  516.  
  517. #if USE_NATIVE_MALLOC
  518.  #if USE_MEMHANDLES
  519.         // use Mac locked handles
  520.         myhdl = RecoverHandle(myptr);
  521.         if (myhdl)
  522.             DisposeHandle(myhdl);
  523.         else
  524.         {
  525.             printf("## Error %d!  Cannot recover handle from ptr! ($%lx)\n",
  526.                     MemError(), myptr);
  527.   #if USE_MEMTAGS
  528.             DebugStr("\pCannot recover handle from ptr");
  529.   #endif // USE_MEMTAGS
  530.         }
  531.  #else
  532.         // use regular Mac pointers
  533.         DisposePtr(myptr);
  534.  #endif // USE_MEMHANDLES
  535. #else
  536.         // The Std C library way...
  537.         free(myptr);
  538. #endif // USE_NATIVE_MALLOC
  539.  
  540.         // remember that this guy was freed for later
  541.         // (if we're tracking, and not in the middle of reclaiming)
  542.         if (gDoMemTracking && !gReclaiming)
  543.         {
  544. #if MALLOC_TRACE
  545.             // point beyond fname again, so that gMallocList & gFreeList match!
  546.             myptr = (void*)(((long)myptr)+32L);
  547. #endif // MALLOC_TRACE
  548.  
  549. #if USE_MEMTAGS
  550.             // point beyond tag again, so that gMallocList & gFreeList match!
  551.             myptr = (void*)(((long)myptr)+4L);
  552. #endif // USE_MEMTAGS
  553. #if USE_MEMHANDLES
  554.             gFreeList[gFreeListCount] = (Ptr)myhdl;
  555. #else
  556.             gFreeList[gFreeListCount] = myptr;
  557. #endif // USE_MEMHANDLES
  558.             if (gFreeListCount < gMallocListSize)
  559.                 gFreeListCount++;
  560.         }
  561.     }
  562. } // POV_free
  563.  
  564.  
  565. // =====================================================================
  566. Boolean POV_need_to_reclaim(void)
  567. {
  568.     return (gMallocListCount > 0);
  569. } // POV_need_to_reclaim
  570.  
  571.  
  572. // =====================================================================
  573. void POV_reclaim(Boolean BeVerbose, DialogPtr progressDialogPtr)
  574. {
  575.     register Ptr    *theMallocListPtr;
  576.     register Ptr    *theFreedListPtr;
  577.     register long     i,j;
  578.     long             min_index, max_index;
  579. #if MALLOC_TRACE
  580.     FILE            *mtfp;
  581. #endif // MALLOC_TRACE
  582.  
  583.     // Let everyone know we're busy in reclaiming mode
  584.     gReclaiming = true;
  585.  
  586.     // anything to do?
  587.     if (gMallocListCount > 0)
  588.     {        
  589.         SetCursor(*GetCursor(watchCursor)); // could take a little while..
  590.  
  591.         // First, remove any entries from the malloc pile if already freed.
  592.         // Do this by scanning the freed pile, and if an entry matches one
  593.         // in malloc pile, delete it.  To help speed things up, keep track of
  594.         // the lowest and highest valid entries in the malloc list, so we don't
  595.         // revisit them in the inner loop (min_index, max_index)
  596.         if (gFreeListCount > 0)
  597.         {
  598.             theFreedListPtr = gFreeList;
  599.  
  600.             min_index = 0;
  601.             max_index = gMallocListCount-1;
  602.             // find starting point
  603.             theMallocListPtr = &gMallocList[min_index];
  604.             while ((*theMallocListPtr == NULL) && (min_index <= max_index))
  605.             {
  606.                 theMallocListPtr++;
  607.                 min_index++;
  608.             }
  609.             // find ending point
  610.             theMallocListPtr = &gMallocList[max_index];
  611.             while ((*theMallocListPtr == NULL) && (max_index > min_index))
  612.             {
  613.                 theMallocListPtr--;
  614.                 max_index--;
  615.             }
  616.  
  617. // printf("## DEBUG; min=%ld  max=%ld total=%ld\n",min_index,max_index,gMallocListCount); // debug
  618.  
  619.             for (i=0; i<gFreeListCount; i++, theFreedListPtr++)
  620.             {
  621.                 // Update the progress bar only occasionally (every 32 loops)
  622.                 if ( progressDialogPtr && !(i & 31) )
  623.                 {
  624.                     // go to the 1/2 way mark in this loop
  625.                     updateProgressDialog(progressDialogPtr, 0, gFreeListCount, i>>1);
  626.                 }
  627.  
  628.                 // check this freed pointer against the malloc list
  629.                 theMallocListPtr = &gMallocList[min_index];
  630.                 for (j = min_index; j<=max_index; j++, theMallocListPtr++)
  631.                 {
  632.                     // is there a malloc entry to check against?
  633.                     if (*theMallocListPtr != NULL)
  634.                     {
  635.                         if (*theMallocListPtr == *theFreedListPtr)
  636.                         { // found it, remove from malloc pile
  637.                             *theMallocListPtr = NULL;
  638.                             break; // out of this for loop
  639.                         }
  640.                     }
  641.                 } // for j
  642.             } // for i
  643.         }
  644.  
  645. #if MALLOC_TRACE
  646.     mtfp = fopen("MallocTrace.Out", "w+");
  647.     fprintf(mtfp, "## Leftover un-freed memory:\n");
  648. #endif // MALLOC_TRACE
  649.  
  650.         // free whatever is left over in the malloc list
  651.         theMallocListPtr = &gMallocList[min_index];
  652.         for (i=min_index; i<max_index; i++, theMallocListPtr++)
  653.         {
  654.             // Update the progress bar only occasionally (every 32 loops)
  655.             if ( progressDialogPtr && !(i & 31) )
  656.             {
  657.                 // do the last 1/2 in this loop
  658.                 updateProgressDialog(progressDialogPtr, 0, gMallocListCount,
  659.                     (gMallocListCount+i) >> 1);
  660.             }
  661.             if (*theMallocListPtr != NULL)
  662.             {
  663. #if MALLOC_TRACE
  664.                 char    * p;
  665.                 p = (char*)((long)*theMallocListPtr)-32L;
  666.                 fprintf(mtfp, "File %s; line %d\n", p+2, *(short*)p);
  667. #endif // MALLOC_TRACE
  668. #if USE_MEMHANDLES
  669.                 // A true handle is stored there, don't mess around, dispose it!
  670.                 DisposeHandle((Handle)*theMallocListPtr);
  671. #else
  672.                 POV_free(*theMallocListPtr);
  673. #endif // USE_MEMHANDLES
  674.             }
  675.         }
  676.  
  677. #if MALLOC_TRACE
  678.     if (mtfp) fclose(mtfp);
  679. #endif // MALLOC_TRACE
  680.  
  681.         if (BeVerbose)
  682.         {
  683.             printf("-- Garbage Collection Statistics:\n");
  684.             printf("--                     malloc()    free()\n");
  685.             printf("--    Max trackable:   %8ld  %8ld\n", gMallocListSize, gMallocListSize);
  686.             printf("--    Total tracked:   %8ld  %8ld\n", gMallocListCount, gFreeListCount);
  687.             if (gEscapedMallocsCount > 0)
  688.             {
  689.                 printf("## Extra untracked: %8ld       ---\n", gEscapedMallocsCount);
  690.                 printf("##\n");
  691.                 printf("## Warning, couldn't track and dispose all memory allocations.\n");
  692.                 printf("## Increase the heap size or increase the application's CNFG\n");
  693.                 printf("## resource value to help alleviate this.\n");
  694.             }
  695.         }
  696.  
  697.         // open some heap space
  698.         (void)CompactMem(FreeMem());
  699.     
  700.         *gMallocList = NULL;
  701.         gMallocListCount = 0;
  702.         *gFreeList = NULL;
  703.         gFreeListCount = 0;
  704.         gEscapedMallocsCount = 0L;
  705.  
  706.         SetCursor(&qd.arrow);
  707.     }
  708.  
  709.     // Let everyone (POV_Free) know we're out of reclaiming mode
  710.     gReclaiming = false;
  711.  
  712. } // POV_reclaim
  713.